package core

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strconv"
)

//CLI 命令行接口
type CLI struct {
	Bc *BlockChain
}

//printUsage 打印使用说明
func (cli *CLI) printUsage() {
	fmt.Println("参数：")
	fmt.Println("addblock -data block_data 添加一个区块到区块链，block_data是数据")
	fmt.Println("printchain 打印区块链中所有的区块")

}

//validateArgs 判断是否有参数，没有参数就打印使用说明
func (cli *CLI) validateArgs() {
	if len(os.Args) < 2 {
		cli.printUsage()
		os.Exit(1)
	}
}

//addBlock 接收数据添加区块
func (cli *CLI) addBlock(data string) {
	cli.Bc.AddBlock(data)
	fmt.Println("创建区块成功！")
}

//printChain 打印区块链的区块
func (cli *CLI) printChain() {
	//获取迭代器
	bci := cli.Bc.Iterator()

	//for循环遍历区块链，直到创世块
	for {
		//获取当前区块
		block := bci.Next()
		fmt.Printf("上一个区块hash: %x\n", block.PrevBlockHash)
		fmt.Printf("本区块数据: %s\n", block.Data)
		fmt.Printf("本区间hash: %x\n", block.Hash)
		//验证工作量
		pow := NewProofOfWork(block)
		fmt.Printf("工作量验证是否通过: %s\n", strconv.FormatBool(pow.Validate()))
		fmt.Println()
		//这里也可以用 len(block.PrevBlockHash) == 0 判断是否到了创世块
		if string(block.Data) == "Genesis Block" {
			break
		}

	}
}

//Run 启动命令行接口
func (cli *CLI) Run() {
	//判断是否有参数
	cli.validateArgs()

	//解析命令行参数
	addBlockCmd := flag.NewFlagSet("addblock", flag.ExitOnError)
	printChainCmd := flag.NewFlagSet("printchain", flag.ExitOnError)

	//添加标志，返回一个参数指针
	addBlockData := addBlockCmd.String("data", "", "区块数据")

	//解析命令，获取参数，参数会存入上面的指针对应的地址里
	switch os.Args[1] {
	case "addblock":
		err := addBlockCmd.Parse(os.Args[2:])
		if err != nil {
			log.Panic(err)
		}
	case "printchain":
		err := printChainCmd.Parse(os.Args[2:])
		if err != nil {
			log.Panic(err)
		}
	default:
		//找不到对应参数就打印使用说明
		cli.printUsage()
		os.Exit(1)
	}

	//这里判断是用来区分获取到了哪个命令，这里是获取到addBlockCmd命令的分支
	//Parsed是判断是否用过Parse解析命令，用过了就返回true
	if addBlockCmd.Parsed() {
		//没有数据就打印帮助信息
		if *addBlockData == "" {
			addBlockCmd.Usage()
			os.Exit(1)
		}
		//有数据就添加区块
		cli.addBlock(*addBlockData)
	}

	//这里是获取到printChainCmd命令的分支
	if printChainCmd.Parsed() {
		cli.printChain()
	}
}
